package ltd.dujiabao.capability.adapter.driven.persistence.rulemng;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
import ltd.dujiabao.capability.domain.rulemng.Rule;
import ltd.dujiabao.capability.domain.rulemng.RuleRepository;
import ltd.dujiabao.capability.domain.rulemng.VersionRule;
import ltd.dujiabao.capability.domain.rulemng.expression.Expression;
import ltd.dujiabao.capability.domain.rulemng.expression.ExpressionFactory;

/**
 * @author : DuJiabao
 * @Project : ddd-capability
 * @Time : 2024/4/13 13:25
 * @Desc :
 */
@Slf4j
@Component
public class RuleRepositoryImpl implements RuleRepository, ApplicationListener<RuleChangedEvent> {
    @Autowired
    private RuleProperties properties;
    private volatile Map<String, Rule> ruleMap = new HashMap<>();

    @Autowired
    private ExpressionFactory expressionFactory;

    public List<Expression> toExpression(List<RuleProperties.Expression> prop) {
        return prop.stream()
                .map(expression -> expressionFactory.build(expression.getModule(), expression.getExpression()))
                .collect(Collectors.toList());
    }

    @Override
    public Rule findByFuncName(String funcName) {
        return ruleMap.get(funcName);
    }

    @Override
    public void onApplicationEvent(RuleChangedEvent event) {
        refresh();
    }

    @PostConstruct
    public void refresh() {
        Map<String, Rule> ruleMap = new HashMap<>();
        for (Map.Entry<String, List<RuleProperties.VersionRule>> entry : properties.getRules().entrySet()) {
            List<VersionRule> versionRules = new ArrayList<>();
            for (RuleProperties.VersionRule versionRuleProp : entry.getValue()) {
                List<Expression> and = toExpression(versionRuleProp.getAnd());
                List<Expression> or = toExpression(versionRuleProp.getOr());
                VersionRule versionRule = new VersionRule(versionRuleProp.getVersion(), and, or);
                versionRules.add(versionRule);
            }
            Rule rule = new Rule(entry.getKey(), versionRules);
            ruleMap.put(rule.getFuncName(), rule);
        }
        this.ruleMap = ruleMap;
        log.info("Finish refresh RuleRepositoryImpl.");
    }
}
